package kam.fire;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.text.util.Linkify;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

public class RoomController extends Activity implements OnGestureListener, OnTouchListener {
	/** Called when the activity is first created. */
	Room room = new Room();
	DatabaseHelper db = DatabaseHelper.getHelper(this);
	KamfireInstance kamfireInstance;
	Options options;
	GestureDetector gd;
	private int roomIndex;
	private ArrayList<Upload> uploads = new ArrayList<Upload>();
	private int UPDATE_DURATION = 30000;
	private int UPDATE_DISPLAY_DURATION = 3000;
	private int roomId;
	private int userIndex;
	private Timer autoUpdate;
	private Timer autoDisplay;
	private final int SWIPE_MIN_DISTANCE = 120;
	private final int SWIPE_MAX_OFF_PATH = 250;
	private final int SWIPE_THRESHOLD_VELOCITY = 200;
	private ArrayList<Message> roomMessages = new ArrayList<Message>();
	String title = "Kamfire - ";
	private String campsite;
	private String apiToken;

	@Override
	protected void onDestroy() {
		super.onDestroy();
		unbindDrawables(findViewById(R.id.ScrollView));
		System.gc();
	}

	private void unbindDrawables(View view) {
		ScrollView scrollview = (ScrollView) view;
		if (scrollview.getBackground() != null) {
			scrollview.getBackground().setCallback(null);
		}

		int childcount = scrollview.getChildCount();
		for (int i = 0; i < childcount; i++) {
			View v = scrollview.getChildAt(i);
			((ViewGroup) v).removeAllViews();
		}

	}

	@Override
	public void onPause() {
		autoUpdate.cancel();
		autoDisplay.cancel();
		super.onPause();
	}

	@Override
	protected void onResume() {
		super.onResume();
		changeTitle();
		autoUpdate = new Timer();
		autoUpdate.schedule(new TimerTask() {
			@Override
			public void run() {
				runOnUiThread(new Runnable() {
					public void run() {
						updateMessagesList(); // also does the inital update
					}
				});
			}
		}, 0, UPDATE_DURATION); // updates evry 30 secs
		
		autoDisplay = new Timer();
		autoDisplay.schedule(new TimerTask() {
			@Override
			public void run() {
				runOnUiThread(new Runnable() {
					public void run() {
						displayMoreMessages(); // 
					}
				});
			}
		}, 0, UPDATE_DISPLAY_DURATION); // updates every 5 secs
		
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.room);
		options = db.getOptions();
		gd = new GestureDetector(this);

		Bundle roomsBundle = getIntent().getExtras();
		roomIndex = (Integer) roomsBundle.getSerializable("ROOM_INDEX");
		campsite = (String) roomsBundle.getSerializable("USER_CAMPSITE");
		apiToken = (String) roomsBundle.getSerializable("USER_APITOKEN");
		userIndex = (Integer) roomsBundle.getSerializable("USER_INDEX");
		kamfireInstance = new KamfireInstance(campsite, apiToken);
		roomId = db.getRoomId(roomIndex);

		changeTitle();
		populateMessagesList();

		ScrollView scrollView = (ScrollView) findViewById(R.id.ScrollView);
		scrollView.setOnTouchListener(this);

		Button postButton = (Button) findViewById(R.id.postbutton);

		postButton.setOnLongClickListener(new OnLongClickListener() {
			public boolean onLongClick(View v) {

				Intent intent = new Intent();
				intent.setType("image/*");
				intent.setAction(Intent.ACTION_GET_CONTENT);
				startActivityForResult(Intent.createChooser(intent, "Select Picture"), 1);

				return true;
			}
		});

	}

	// used when posting images
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (resultCode == RESULT_OK) {
			if (requestCode == 1) {
				Uri selectedImageUri = data.getData();
				String selectedImagePath = getPath(selectedImageUri);
				kamfireInstance.postImageUpload(roomId, selectedImagePath);
				updateMessagesList();
			}
		}
	}

	private void populateMessagesList() {

		if (checkConnection()) {
			LinearLayout lLayout;
			lLayout = (LinearLayout) findViewById(R.id.MessageLayout);
			lLayout.removeAllViews();
			new GetMessagesFromDB().execute();
		
		} else {
			noConnection();
		}
	}

	private void updateMessagesList() {

		if (checkConnection()) {
			new GetMessagesFromCampfire().execute();
		} else {
			noConnection();
		}
	}

	private void addMessagesToTable(ArrayList<Message> messageList) {

		db.addMessages(messageList); // adds the list of new messages to the
										// local table
	}

	private void updateRoom(List<Message> messageList) {
		for (Message message : messageList) {
			if (message.getUserId() > 0) {
				writeName(message);
				writeMessage(message);
				writeDate(message);
			}
		}
		scrollDown();
	}

	private void displayMoreMessages(){
		if(roomMessages.size()>10){
			updateRoom(roomMessages.subList(0, 9));
			roomMessages.subList(0, 9).clear();
		}
		else if(roomMessages.size()>0){
			updateRoom(roomMessages);
			roomMessages.clear();
		}
	}

	private void writeName(Message message) {
		TextView nameView = new TextView(this);
		LinearLayout lLayout;
		lLayout = (LinearLayout) findViewById(R.id.MessageLayout);
		lLayout.addView(nameView);
		nameView.setTextColor(Color.WHITE);

		nameView.setText(db.getUserName((message.getUserId())));
		nameView.append(": ");
	}

	private void writeMessage(Message message) {

		TextView messageView = new TextView(this);
		if (message.getType().equals("UploadMessage")) {

			writeUploadMessage(message);

		}
		LinearLayout lLayout;
		lLayout = (LinearLayout) findViewById(R.id.MessageLayout);
		lLayout.addView(messageView);
		messageView.setTextColor(Color.WHITE);

		if (message.getType().equals("EnterMessage")) {
			messageView.setText("has entered the room.");
		}
		if (message.getType().equals("KickMessage")) {
			messageView.setText("has left the room.");
		}
		if (message.getType().equals("TextMessage")) {
			messageView.setAutoLinkMask(Linkify.ALL);
			messageView.setText(message.getBody());
		}

		if (message.getType().equals("TopicChangeMessage")) {
			messageView.setText("Topic Changed: ");
			messageView.append(message.getBody());
		}
	}

	private void writeUploadMessage(Message message) {
		LinearLayout lLayout;
		TextView messageView = new TextView(this);
		messageView.setTextColor(Color.WHITE);

		// check if upload is in uploads list from db
		Upload upload = getUploadFromUploads(message.getId());
		if (upload == null) {
			upload = kamfireInstance.getUploadRequest(roomId, message.getId());
			if (upload != null) {
				db.addUpload(upload);
			}
		}
		// if ==null, upload = upload from campfire
		if (upload != null) {
			// upload is not downloaded to sd card and is autodownload is on
			File downloadedFile = kamfireInstance.getDownloadedFile(upload.getId());
			if (downloadedFile == null && options.getAutoSaveFiles()) {
				kamfireInstance.saveDataFile(upload);
				downloadedFile = kamfireInstance.getDownloadedFile(upload.getId());
			}// if downloaded file exits display from file
			if (downloadedFile != null) {
				displayFile(downloadedFile);
			} // if file is not on card and no auto download, display from web
			else if (upload.getType().equals("image/jpeg") || upload.getType().equals("application/octet-stream")
					|| upload.getType().equals("image/jpg") || upload.getType().equals("image/gif")
					|| upload.getType().equals("image/png")) {

				displayUploadFromWeb(upload);
			}
			messageView.setText(message.getBody());
			lLayout = (LinearLayout) findViewById(R.id.MessageLayout);
			lLayout.addView(messageView);
		}
	}

	private Upload getUploadFromUploads(int id) {
		for (Upload upload : uploads) {
			if (upload.getId() == id) {
				return upload;
			}
		}
		return null;
	}

	private void displayFile(final File downloadedFile) {
		LinearLayout lLayout;
		lLayout = (LinearLayout) findViewById(R.id.MessageLayout);
		final ImageView imageView = new ImageView(this);
		// final ImageButton imageView = new ImageButton(this);
		lLayout.addView(imageView);
		imageView.setImageURI(Uri.fromFile(downloadedFile));
		imageView.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				Intent intent = new Intent(Intent.ACTION_VIEW);
				intent.setClassName(RoomController.this, FullScreenController.class.getName());
				Bundle imageBundle = new Bundle();
				imageBundle.putSerializable("IMAGE_TYPE",
						downloadedFile.getPath().substring(downloadedFile.getPath().length() - 4));
				imageBundle.putSerializable("IMAGE_FILE", downloadedFile);
				intent.putExtras(imageBundle);
				RoomController.this.startActivity(intent);
			}
		});

		imageView.setOnLongClickListener(new OnLongClickListener() {
			public boolean onLongClick(View v) {

				Toast.makeText(getApplicationContext(), "Image already saved in /Kamfire", Toast.LENGTH_LONG).show();
				return true;
			}
		});

	}

	private void displayUploadFromWeb(final Upload upload) {

		LinearLayout lLayout;
		lLayout = (LinearLayout) findViewById(R.id.MessageLayout);

		final ImageView imageView = new ImageView(this);
		lLayout.addView(imageView);
		imageView.setImageBitmap(kamfireInstance.loadImageFromWeb(upload.getUrl(), this));
		imageView.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				Intent intent = new Intent(Intent.ACTION_VIEW);
				intent.setClassName(RoomController.this, FullScreenController.class.getName());
				Bundle imageBundle = new Bundle();
				imageBundle.putSerializable("IMAGE_URL", upload.getUrl());
				imageBundle.putSerializable("IMAGE_TYPE", upload.getType());
				imageBundle.putSerializable("IMAGE_SIZE", upload.getSize());
				imageBundle.putSerializable("USER_CAMPSITE", campsite);
				imageBundle.putSerializable("USER_APITOKEN", apiToken);

				intent.putExtras(imageBundle);
				RoomController.this.startActivity(intent);
			}
		});

		imageView.setOnLongClickListener(new OnLongClickListener() {
			public boolean onLongClick(View v) {
				AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(RoomController.this);

				// set title
				alertDialogBuilder.setTitle("Save Image");

				// set dialog message
				alertDialogBuilder.setMessage("Save Image to SD card?").setCancelable(false)
						.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int id) {
								// if this button is clicked, close
								// dialog and save image
								dialog.cancel();
								boolean success = false;
								success = kamfireInstance.saveDataFile(upload);

								if (success) {
									Toast.makeText(getApplicationContext(), "Saved with success", Toast.LENGTH_LONG)
											.show();
								} else {
									Toast.makeText(getApplicationContext(), "Error during image saving",
											Toast.LENGTH_LONG).show();
								}

							}

						}).setNegativeButton("No", new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int id) {
								// if this button is clicked, just close
								// the dialog box and do nothing
								dialog.cancel();

							}
						});

				// create alert dialog
				AlertDialog alertDialog = alertDialogBuilder.create();

				// show it
				alertDialog.show();
				return true;
			}
		});

	}

	private void writeDate(Message message) {

		TextView date = new TextView(this);
		LinearLayout lLayout;
		lLayout = (LinearLayout) findViewById(R.id.MessageLayout);
		lLayout.addView(date);
		date.setTextColor(Color.WHITE);
		date.setText(kamfireInstance.convertDate(message.getDate()));

		date.setGravity(5);
	}

	public void postMessage(View v) {
		EditText textField = (EditText) findViewById(R.id.EditText);
		String text = textField.getText().toString();
		if (checkConnection()) {
			if (text.trim() != "") {
				Message message = new Message();
				message.setBody(text);
				message.setType("TextMessage");
				kamfireInstance.postTextMessage(roomId, message);
				textField.setText("");
				updateMessagesList();
			}
		} else {
			noConnection();
		}
	}

	public String getPath(Uri contentUri) {
		String res = null;
		String[] proj = { MediaStore.Images.Media.DATA };
		Cursor cursor = getContentResolver().query(contentUri, proj, null, null, null);
		if (cursor.moveToFirst()) {
			;
			int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
			res = cursor.getString(column_index);
		}
		cursor.close();
		return res;
	}

	// =========================Button OverRides
	/**
	 * create options menu
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// group, item id, order, name
		menu.add(0, 0, 0, "Settings");
		return true;
	}

	/**
	 * handle the options item click
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle item selection
		switch (item.getItemId()) {
		case 0:
			gotToOptions();
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}

	private void gotToOptions() {
		Intent intent = new Intent(Intent.ACTION_VIEW);
		intent.setClassName(this, OptionsController.class.getName());

		this.startActivity(intent);

	}

	// ===================Touch Control
	public boolean onTouch(View v, MotionEvent event) {
		onTouchEvent(event); // throw to onTouchEvent

		return false;
	}

	@Override
	public boolean onTouchEvent(MotionEvent me) {
		return gd.onTouchEvent(me); // gd = gesturedetector
	}

	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
		try {
			if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
				return false;
			// right to left swipe
			if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
				goToNextRoom();
			} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
				goToPreviousRoom();
			}
		} catch (Exception e) {
			// nothing
		}
		return false;
	}

	public boolean onDown(MotionEvent arg0) {
		// TODO Auto-generated method stub
		return false;
	}

	public void onLongPress(MotionEvent arg0) {
		// TODO Auto-generated method stub

	}

	public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) {
		// TODO Auto-generated method stub
		return false;
	}

	public void onShowPress(MotionEvent arg0) {
		// TODO Auto-generated method stub

	}

	public boolean onSingleTapUp(MotionEvent arg0) {
		// TODO Auto-generated method stub
		return false;
	}

	// =========================Utility
	private void goToNextRoom() {
		ArrayList<Integer> roomIndexes = db.getRoomIndexList(userIndex);

		if (roomIndex<roomIndexes.get(roomIndexes.size()-1)) {
			roomIndex = roomIndexes.listIterator(roomIndexes.indexOf(roomIndex)+1).next();
		} else {
			roomIndex = roomIndexes.get(0);
		}
		roomId = db.getRoomId(roomIndex);
		changeTitle();
		populateMessagesList();
	}

	private void goToPreviousRoom() {
		ArrayList<Integer> roomIndexes = db.getRoomIndexList(userIndex);
		if (roomIndexes.listIterator(roomIndexes.indexOf(roomIndex)).hasPrevious()) {
			roomIndex = roomIndexes.listIterator(roomIndexes.indexOf(roomIndex)).previous();
		} else {
			roomIndex = roomIndexes.get(roomIndexes.size()-1);
		}
		roomId = db.getRoomId(roomIndex);
		changeTitle();
		populateMessagesList();

	}

	private void noConnection() {
		Toast toast = Toast.makeText(this, "No Internet Service", Toast.LENGTH_SHORT);
		toast.show();
	}

	private void errorConnection() {
		Toast toast = Toast.makeText(this, "Error retrieving data", Toast.LENGTH_SHORT);
		toast.show();
	}

	private boolean checkConnection() {
		ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
		if (networkInfo != null && networkInfo.isConnected()) {
			return true;
		} else {
			return false;
		}

	}

	private void changeTitle() {
		title = "Kamfire - " + db.getRoomByIndex(roomIndex).getName();
		setTitle(title); // android method

	}

	private void scrollDown() {
		final Handler handler = new Handler();
		new Thread(new Runnable() {
			public void run() {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
				}
				handler.post(new Runnable() {
					public void run() {
						ScrollView scrollView;
						scrollView = (ScrollView) findViewById(R.id.ScrollView);
						scrollView.fullScroll(View.FOCUS_DOWN);
					}
				});
			}
		}).start();
	}

	// ==============Seperate Threads
	private class GetMessagesFromCampfire extends AsyncTask<Void, Boolean, ArrayList<Message>> {
		int lastMessage;
		ProgressDialog dialog;
		protected void onPreExecute() {
			lastMessage = db.getLastMessage(roomIndex);
			if (lastMessage==0){
				dialog = ProgressDialog.show(RoomController.this, "", "Loading...");
			}
		}

		@Override
		protected ArrayList<Message> doInBackground(Void... params) {
			
			
			boolean b = kamfireInstance.populateMessages(roomId, lastMessage);
			ArrayList<Message> messageList = null;
			if (b) {
				messageList = kamfireInstance.getMessages();
			} else {
				errorConnection();

			}
			return messageList;
		}

		// onPostExecute displays the results of the AsyncTask.
		protected void onPostExecute(ArrayList<Message> messageList) {
			if (messageList.size() > 0) {
				roomMessages.addAll(messageList);
				addMessagesToTable(messageList);
			}
			if (dialog!= null && dialog.isShowing()) {
				dialog.dismiss();
			}

		}

	}

	private class GetMessagesFromDB extends AsyncTask<Void, Boolean, ArrayList<Message>> {
		ProgressDialog dialog;

		protected void onPreExecute() {
			dialog = ProgressDialog.show(RoomController.this, "", "Loading...");
		}

		@Override
		protected ArrayList<Message> doInBackground(Void... params) {
			
			ArrayList<Message> messageList = db.getMessagesByRoom(roomIndex);
			uploads = db.getUploadsByRoom(roomIndex);
			return messageList;
		}

		// onPostExecute displays the results of the AsyncTask.
		protected void onPostExecute(ArrayList<Message> messageList) {
			roomMessages.addAll(messageList);
			displayMoreMessages();
			if (dialog.isShowing()) {
				dialog.dismiss();
			}
		}

	}

}
